# AI智能化功能引擎
import logging
from datetime import datetime, timedelta
from decimal import Decimal
from typing import List, Dict, Any, Optional
from django.db.models import Count, Sum, Avg, Q, F
from django.utils import timezone
from django.contrib.auth.models import User

from .models import Asset, AssetCategory, Department, MaintenanceRecord, AssetBorrow
from .models_ai import AssetRecommendation, AssetAnomalyDetection, PredictiveMaintenanceModel, AssetUtilizationAnalysis

logger = logging.getLogger(__name__)


class AIRecommendationEngine:
    """AI推荐引擎"""
    
    def __init__(self):
        self.confidence_threshold = 0.6  # 推荐置信度阈值
        
    def generate_maintenance_recommendations(self, user: User, asset: Asset = None) -> List[AssetRecommendation]:
        """生成维修推荐"""
        recommendations = []
        
        # 如果指定了资产，只为该资产生成推荐
        if asset:
            assets = [asset]
        else:
            # 获取所有在用资产
            assets = Asset.objects.filter(status='in_use')
        
        for asset in assets:
            # 基于维修历史的推荐
            maintenance_rec = self._analyze_maintenance_history(asset)
            if maintenance_rec and maintenance_rec['confidence'] >= self.confidence_threshold:
                recommendation = AssetRecommendation.objects.create(
                    user=user,
                    recommendation_type='maintenance',
                    title=f'建议对资产 {asset.name} 进行预防性维修',
                    description=maintenance_rec['description'],
                    asset=asset,
                    confidence_score=maintenance_rec['confidence'],
                    priority=maintenance_rec['priority'],
                    recommendation_data=maintenance_rec['data']
                )
                recommendations.append(recommendation)
        
        return recommendations
    
    def generate_replacement_recommendations(self, user: User, department: Department = None) -> List[AssetRecommendation]:
        """生成更换推荐"""
        recommendations = []
        
        # 获取需要分析的资产
        assets_query = Asset.objects.all()
        if department:
            assets_query = assets_query.filter(department=department)
        
        for asset in assets_query:
            # 基于成本效益分析的更换推荐
            replacement_rec = self._analyze_replacement_need(asset)
            if replacement_rec and replacement_rec['confidence'] >= self.confidence_threshold:
                recommendation = AssetRecommendation.objects.create(
                    user=user,
                    recommendation_type='replacement',
                    title=f'建议考虑更换资产 {asset.name}',
                    description=replacement_rec['description'],
                    asset=asset,
                    department=department,
                    confidence_score=replacement_rec['confidence'],
                    priority=replacement_rec['priority'],
                    recommendation_data=replacement_rec['data']
                )
                recommendations.append(recommendation)
        
        return recommendations
    
    def generate_optimization_recommendations(self, user: User, category: AssetCategory = None) -> List[AssetRecommendation]:
        """生成优化推荐"""
        recommendations = []
        
        # 基于利用率分析的优化推荐
        utilization_recs = self._analyze_utilization_optimization(category)
        for rec in utilization_recs:
            if rec['confidence'] >= self.confidence_threshold:
                recommendation = AssetRecommendation.objects.create(
                    user=user,
                    recommendation_type='optimization',
                    title=rec['title'],
                    description=rec['description'],
                    category=category,
                    confidence_score=rec['confidence'],
                    priority=rec['priority'],
                    recommendation_data=rec['data']
                )
                recommendations.append(recommendation)
        
        return recommendations
    
    def _analyze_maintenance_history(self, asset: Asset) -> Optional[Dict[str, Any]]:
        """分析维修历史"""
        try:
            # 获取过去12个月的维修记录
            twelve_months_ago = timezone.now() - timedelta(days=365)
            maintenance_records = MaintenanceRecord.objects.filter(
                asset=asset,
                created_at__gte=twelve_months_ago
            ).order_by('-created_at')
            
            if not maintenance_records.exists():
                return None
            
            # 计算维修频率
            maintenance_count = maintenance_records.count()
            avg_interval = 365 / maintenance_count if maintenance_count > 0 else 365
            
            # 获取最后一次维修时间
            last_maintenance = maintenance_records.first()
            days_since_last = (timezone.now() - last_maintenance.created_at).days
            
            # 计算维修成本趋势
            total_cost = maintenance_records.aggregate(total=Sum('actual_cost'))['total'] or 0
            avg_cost = total_cost / maintenance_count if maintenance_count > 0 else 0
            
            # 判断是否需要预防性维修
            confidence = 0.0
            priority = 'medium'
            description = ""
            
            if days_since_last > avg_interval * 0.8:
                confidence += 0.4
                description += f"距离上次维修已过去{days_since_last}天，接近平均维修间隔({avg_interval:.0f}天)。"
            
            if maintenance_count >= 3:
                # 分析维修频率趋势
                recent_records = maintenance_records[:3]
                recent_interval = sum([
                    (recent_records[i].created_at - recent_records[i+1].created_at).days
                    for i in range(len(recent_records)-1)
                ]) / (len(recent_records)-1) if len(recent_records) > 1 else avg_interval
                
                if recent_interval < avg_interval * 0.7:
                    confidence += 0.3
                    priority = 'high'
                    description += f"维修频率增加，建议进行深度检查。"
            
            if avg_cost > 1000:  # 高维修成本
                confidence += 0.2
                description += f"平均维修成本较高(¥{avg_cost:.2f})，建议预防性维护。"
            
            if confidence >= self.confidence_threshold:
                return {
                    'confidence': min(confidence, 1.0),
                    'priority': priority,
                    'description': description,
                    'data': {
                        'maintenance_count': maintenance_count,
                        'avg_interval': avg_interval,
                        'days_since_last': days_since_last,
                        'avg_cost': float(avg_cost),
                        'total_cost': float(total_cost)
                    }
                }
            
            return None
            
        except Exception as e:
            logger.error(f"分析维修历史时出错: {e}")
            return None
    
    def _analyze_replacement_need(self, asset: Asset) -> Optional[Dict[str, Any]]:
        """分析更换需求"""
        try:
            # 计算资产年龄
            if not asset.purchase_date:
                return None
            
            asset_age = (timezone.now().date() - asset.purchase_date).days / 365
            
            # 获取维修记录
            maintenance_records = MaintenanceRecord.objects.filter(asset=asset)
            total_maintenance_cost = maintenance_records.aggregate(
                total=Sum('actual_cost')
            )['total'] or 0
            
            # 计算维修成本占购买价格的比例
            if asset.purchase_price and asset.purchase_price > 0:
                maintenance_ratio = total_maintenance_cost / asset.purchase_price
            else:
                maintenance_ratio = 0
            
            confidence = 0.0
            priority = 'medium'
            description = ""
            
            # 基于年龄的分析
            if asset_age > 5:  # 超过5年
                confidence += 0.3
                description += f"资产已使用{asset_age:.1f}年，接近更换周期。"
                
                if asset_age > 8:  # 超过8年
                    confidence += 0.2
                    priority = 'high'
                    description += "资产年龄较长，建议优先考虑更换。"
            
            # 基于维修成本的分析
            if maintenance_ratio > 0.5:  # 维修成本超过购买价格50%
                confidence += 0.4
                priority = 'high'
                description += f"累计维修成本已达购买价格的{maintenance_ratio*100:.1f}%，更换可能更经济。"
            elif maintenance_ratio > 0.3:
                confidence += 0.2
                description += f"维修成本占比较高({maintenance_ratio*100:.1f}%)，建议评估更换。"
            
            # 基于维修频率的分析
            recent_maintenance = maintenance_records.filter(
                created_at__gte=timezone.now() - timedelta(days=180)
            ).count()
            
            if recent_maintenance >= 3:  # 半年内维修3次以上
                confidence += 0.3
                description += f"近半年维修{recent_maintenance}次，频率较高。"
            
            if confidence >= self.confidence_threshold:
                return {
                    'confidence': min(confidence, 1.0),
                    'priority': priority,
                    'description': description,
                    'data': {
                        'asset_age': asset_age,
                        'maintenance_ratio': maintenance_ratio,
                        'total_maintenance_cost': float(total_maintenance_cost),
                        'recent_maintenance_count': recent_maintenance
                    }
                }
            
            return None
            
        except Exception as e:
            logger.error(f"分析更换需求时出错: {e}")
            return None
    
    def _analyze_utilization_optimization(self, category: AssetCategory = None) -> List[Dict[str, Any]]:
        """分析利用率优化"""
        recommendations = []
        
        try:
            # 获取资产查询集
            assets_query = Asset.objects.all()
            if category:
                assets_query = assets_query.filter(category=category)
            
            # 分析闲置资产
            idle_assets = assets_query.filter(status='idle')
            if idle_assets.count() > 0:
                recommendations.append({
                    'title': f'发现{idle_assets.count()}项闲置资产需要优化配置',
                    'description': f'建议重新分配或考虑共享使用这些闲置资产，提高资产利用率。',
                    'confidence': 0.8,
                    'priority': 'medium',
                    'data': {
                        'idle_count': idle_assets.count(),
                        'idle_assets': list(idle_assets.values('id', 'name', 'asset_number'))
                    }
                })
            
            # 分析借用频率低的资产
            low_usage_assets = []
            for asset in assets_query.filter(status='in_use'):
                borrow_count = AssetBorrow.objects.filter(
                    asset=asset,
                    created_at__gte=timezone.now() - timedelta(days=90)
                ).count()
                
                if borrow_count == 0:
                    low_usage_assets.append(asset)
            
            if len(low_usage_assets) > 0:
                recommendations.append({
                    'title': f'发现{len(low_usage_assets)}项低使用率资产',
                    'description': f'这些资产在过去90天内未被借用，建议评估是否需要重新配置。',
                    'confidence': 0.7,
                    'priority': 'low',
                    'data': {
                        'low_usage_count': len(low_usage_assets),
                        'assets': [{'id': a.id, 'name': a.name, 'asset_number': a.asset_number} for a in low_usage_assets]
                    }
                })
            
            return recommendations
            
        except Exception as e:
            logger.error(f"分析利用率优化时出错: {e}")
            return []


class AnomalyDetectionService:
    """异常检测服务"""
    
    def __init__(self):
        self.detection_threshold = 0.7  # 异常检测置信度阈值
    
    def detect_usage_anomalies(self, asset: Asset) -> Optional[AssetAnomalyDetection]:
        """检测使用模式异常"""
        try:
            # 分析借用模式
            recent_borrows = AssetBorrow.objects.filter(
                asset=asset,
                created_at__gte=timezone.now() - timedelta(days=90)
            ).order_by('-created_at')
            
            if recent_borrows.count() < 3:
                return None
            
            # 计算借用间隔
            intervals = []
            borrows_list = list(recent_borrows)
            for i in range(len(borrows_list) - 1):
                interval = (borrows_list[i].created_at - borrows_list[i+1].created_at).days
                intervals.append(interval)
            
            if not intervals:
                return None
            
            avg_interval = sum(intervals) / len(intervals)
            
            # 检测异常间隔
            anomalous_intervals = [i for i in intervals if abs(i - avg_interval) > avg_interval * 0.5]
            
            if len(anomalous_intervals) / len(intervals) > 0.3:  # 30%以上的间隔异常
                confidence = min(len(anomalous_intervals) / len(intervals), 1.0)
                
                anomaly = AssetAnomalyDetection.objects.create(
                    asset=asset,
                    anomaly_type='usage_pattern',
                    severity='medium',
                    description=f'资产使用模式异常，借用间隔波动较大',
                    confidence_score=confidence,
                    detection_algorithm='usage_pattern_analysis',
                    anomaly_data={
                        'avg_interval': avg_interval,
                        'anomalous_intervals': anomalous_intervals,
                        'total_intervals': len(intervals)
                    }
                )
                return anomaly
            
            return None
            
        except Exception as e:
            logger.error(f"检测使用异常时出错: {e}")
            return None
    
    def detect_cost_anomalies(self, maintenance_records: List[MaintenanceRecord]) -> List[AssetAnomalyDetection]:
        """检测成本异常"""
        anomalies = []
        
        try:
            if len(maintenance_records) < 3:
                return anomalies
            
            # 计算平均成本
            costs = [float(record.actual_cost or 0) for record in maintenance_records if record.actual_cost]
            if not costs:
                return anomalies
            
            avg_cost = sum(costs) / len(costs)
            
            # 检测异常高成本
            for record in maintenance_records:
                if record.actual_cost and record.actual_cost > avg_cost * 2:
                    confidence = min((record.actual_cost / avg_cost - 1), 1.0)
                    
                    anomaly = AssetAnomalyDetection.objects.create(
                        asset=record.asset,
                        anomaly_type='cost_anomaly',
                        severity='high' if record.actual_cost > avg_cost * 3 else 'medium',
                        description=f'维修成本异常高: ¥{record.actual_cost}，超过平均成本{record.actual_cost/avg_cost:.1f}倍',
                        confidence_score=confidence,
                        detection_algorithm='cost_anomaly_analysis',
                        anomaly_data={
                            'actual_cost': float(record.actual_cost),
                            'avg_cost': avg_cost,
                            'cost_ratio': float(record.actual_cost / avg_cost),
                            'maintenance_id': record.id
                        }
                    )
                    anomalies.append(anomaly)
            
            return anomalies
            
        except Exception as e:
            logger.error(f"检测成本异常时出错: {e}")
            return []
    
    def detect_frequency_anomalies(self, asset: Asset) -> Optional[AssetAnomalyDetection]:
        """检测维修频率异常"""
        try:
            # 获取过去12个月的维修记录
            twelve_months_ago = timezone.now() - timedelta(days=365)
            maintenance_records = MaintenanceRecord.objects.filter(
                asset=asset,
                created_at__gte=twelve_months_ago
            ).order_by('-created_at')
            
            maintenance_count = maintenance_records.count()
            
            # 获取同类别资产的平均维修频率
            category_avg = MaintenanceRecord.objects.filter(
                asset__category=asset.category,
                created_at__gte=twelve_months_ago
            ).values('asset').annotate(
                count=Count('id')
            ).aggregate(avg_count=Avg('count'))['avg_count'] or 0
            
            # 检测频率异常
            if maintenance_count > category_avg * 1.5:  # 超过同类别平均1.5倍
                confidence = min((maintenance_count / category_avg - 1), 1.0)
                
                anomaly = AssetAnomalyDetection.objects.create(
                    asset=asset,
                    anomaly_type='maintenance_frequency',
                    severity='high' if maintenance_count > category_avg * 2 else 'medium',
                    description=f'维修频率异常高: {maintenance_count}次/年，超过同类别平均{maintenance_count/category_avg:.1f}倍',
                    confidence_score=confidence,
                    detection_algorithm='frequency_anomaly_analysis',
                    anomaly_data={
                        'maintenance_count': maintenance_count,
                        'category_avg': category_avg,
                        'frequency_ratio': maintenance_count / category_avg if category_avg > 0 else 0
                    }
                )
                return anomaly
            
            return None
            
        except Exception as e:
            logger.error(f"检测频率异常时出错: {e}")
            return None


class PredictiveMaintenanceService:
    """预测性维护服务"""
    
    def predict_maintenance_needs(self, asset: Asset, days_ahead: int = 30) -> Dict[str, Any]:
        """预测维护需求"""
        try:
            # 获取适用的预测模型
            model = PredictiveMaintenanceModel.objects.filter(
                category=asset.category,
                is_active=True
            ).first()
            
            if not model:
                return self._default_prediction(asset, days_ahead)
            
            # 使用模型进行预测
            predicted_date = model.predict_maintenance_date(asset)
            
            if predicted_date:
                days_until = (predicted_date.date() - timezone.now().date()).days
                
                return {
                    'predicted_date': predicted_date.date(),
                    'days_until': days_until,
                    'confidence': model.accuracy,
                    'model_type': model.model_type,
                    'recommendation': self._generate_maintenance_recommendation(days_until)
                }
            else:
                return self._default_prediction(asset, days_ahead)
                
        except Exception as e:
            logger.error(f"预测维护需求时出错: {e}")
            return self._default_prediction(asset, days_ahead)
    
    def _default_prediction(self, asset: Asset, days_ahead: int) -> Dict[str, Any]:
        """默认预测逻辑"""
        # 基于历史维修记录的简单预测
        maintenance_records = MaintenanceRecord.objects.filter(
            asset=asset,
            status='completed'
        ).order_by('-completed_at')
        
        if maintenance_records.count() >= 2:
            # 计算平均维修间隔
            intervals = []
            records_list = list(maintenance_records[:5])  # 取最近5次维修
            
            for i in range(len(records_list) - 1):
                interval = (records_list[i].completed_at - records_list[i+1].completed_at).days
                intervals.append(interval)
            
            if intervals:
                avg_interval = sum(intervals) / len(intervals)
                last_maintenance = records_list[0].completed_at
                predicted_date = last_maintenance.date() + timedelta(days=avg_interval)
                days_until = (predicted_date - timezone.now().date()).days
                
                return {
                    'predicted_date': predicted_date,
                    'days_until': days_until,
                    'confidence': 0.6,  # 基础预测置信度
                    'model_type': 'historical_average',
                    'recommendation': self._generate_maintenance_recommendation(days_until)
                }
        
        # 如果没有足够的历史数据，使用默认间隔
        default_interval = 365  # 默认一年维修一次
        predicted_date = timezone.now().date() + timedelta(days=default_interval)
        
        return {
            'predicted_date': predicted_date,
            'days_until': default_interval,
            'confidence': 0.3,  # 低置信度
            'model_type': 'default',
            'recommendation': '建议建立维修记录以提高预测准确性'
        }
    
    def _generate_maintenance_recommendation(self, days_until: int) -> str:
        """生成维护建议"""
        if days_until <= 7:
            return '建议立即安排维修'
        elif days_until <= 30:
            return '建议在本月内安排维修'
        elif days_until <= 90:
            return '建议在本季度内安排维修'
        else:
            return '暂时无需安排维修'


# 全局AI服务实例
ai_recommendation_engine = AIRecommendationEngine()
anomaly_detection_service = AnomalyDetectionService()
predictive_maintenance_service = PredictiveMaintenanceService()